package com.dlyk.config;

import com.dlyk.constant.Constants;
import com.dlyk.filter.TokenVerifyFilter;
import com.dlyk.handle.MyAccessDeniedHandler;
import com.dlyk.handle.MyAuthenticationFailureHandler;
import com.dlyk.handle.MyAuthenticationSuccessHandler;
import com.dlyk.handle.MyLogoutSuccessHandler;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Arrays;

@EnableMethodSecurity  // 开启方法级别的权限检查
@Configuration
public class SecurityConfig {
    @Autowired
    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;

    @Autowired
    private MyAuthenticationFailureHandler myAuthenticationFailureHandler;

    @Autowired
    private TokenVerifyFilter tokenVerifyFilter;

    @Autowired
    private MyLogoutSuccessHandler myLogoutSuccessHandler;

    @Resource
    private MyAccessDeniedHandler myAccessDeniedHandler;

    /**
     * 配置加密器
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    /**
     * 实现跨域
     * @return
     */
    @Bean
    public CorsConfigurationSource configurationSource(){
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowedOrigins(Arrays.asList("*")); // 允许任何请求来源
        corsConfiguration.setAllowedMethods(Arrays.asList("*")); // 允许任何请求方法
        corsConfiguration.setAllowedHeaders(Arrays.asList("*")); // 允许任何请求头

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**",corsConfiguration);

        return source;
    }

    /**
     * 配置用户登录
     * @param httpSecurity
     * @return
     * @throws Exception
     */
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity,CorsConfigurationSource configurationSource) throws Exception {
        return httpSecurity
                .formLogin((formLogin)->{
                    formLogin.loginProcessingUrl(Constants.LOGIN_URI)  // 登录处理地址
                             .usernameParameter("loginAct")
                             .passwordParameter("loginPwd")
                             .successHandler(myAuthenticationSuccessHandler)
                             .failureHandler(myAuthenticationFailureHandler);
                })
                // 请求认证
                .authorizeHttpRequests(authorization -> {
                    authorization
                            .requestMatchers("/api/login").permitAll()   // 对登录进行放行
                            .anyRequest().authenticated();  // 任何用户都需要登录后才能访问
                })

                .csrf((csrf)->{
                    csrf.disable();    // 禁用跨域请求伪造
                })

                .cors(cors->{
                    cors.configurationSource(configurationSource);
                })

                // 添加Session策略
                .sessionManagement((session)->{
                    session.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
                })

                // 添加自定义的过滤器
                .addFilterBefore(tokenVerifyFilter, LogoutFilter.class)

                // 退出登录
                .logout((logout)->{
                    logout.logoutUrl("/api/logout")
                          .logoutSuccessHandler(myLogoutSuccessHandler);
                })
                .exceptionHandling((exceptionHandling)->{
                    exceptionHandling.accessDeniedHandler(myAccessDeniedHandler);
                })
                .build();
    }
}
